package com.wonder.bean.kingdee;

import com.vtuzx.core.VtuzxException;
import com.vtuzx.core.bean.dto.VtuzxMap;
import com.vtuzx.core.constant.IVtuzxConst;
import com.vtuzx.core.utils.VtuzxUtil;
import com.wonder.constant.KingdeeServiceKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.http.*;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import java.io.File;
import java.io.FileInputStream;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

public class VtuzxKingdeeCloudClient {
    /** kingdee session key */
    private final static String SESSION_KEY = "kdservice-sessionid";
    /** asp session key */
    private final static String ASP_SESSION_KEY = "ASP.NET_SessionId";
    /** 单次文件上传长度限制 */
    private final static int READ_MAX_LEN = 1024 * 1024;
    /** 日志 */
    private static final Logger _logger = LoggerFactory.getLogger(VtuzxKingdeeCloudClient.class);
    /** 账号信息 */
    private final KingdeeAccount _account;
    /** 登录Token */
    private VtuzxKingdeeCloudToken _token;

    /**
     * 初始化方法
     *
     * @param account 账号
     */
    public VtuzxKingdeeCloudClient(KingdeeAccount account) {
        this._account= account;
    }

    /**
     * 客户端登录
     */
    public VtuzxKingdeeCloudClient login() throws VtuzxException {
        MultiValueMap<String, Object> form = new LinkedMultiValueMap<>();
        setParameter(form, String.format("[\"%s\",\"%s\",\"%s\",%d]", _account.getDataCenterId(), _account.getAccount(), _account.getPassword(), _account.getLang()));

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.MULTIPART_FORM_DATA);
        HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(form, headers);
        RestTemplate restTemplate = new RestTemplate();
        String url = String.format("%s%s", _account.getUrl(), KingdeeServiceKey.ValidateUser);
        ResponseEntity<String> result = restTemplate.postForEntity(url, httpEntity, String.class);
        if (!HttpStatus.OK.equals(result.getStatusCode()) || result.getBody() == null) {
            throw new VtuzxException(IVtuzxConst.Msg_E_system);
        }
        VtuzxMap resultMap = VtuzxUtil.str2Json(result.getBody());
        int resultType = VtuzxUtil.getInt(resultMap, "LoginResultType");
        if (resultType == 1) {
            List<String> cookies = result.getHeaders().get("Set-Cookie");
            String serviceSessionId = "";
            String netSessionId = "";
            if (cookies != null) {
                for(String cookie: cookies) {
                    String keyVal = cookie.split(";")[0];
                    String[] keyVals = keyVal.split("=");
                    String key = keyVals[0];
                    String value = keyVals[1];
                    if (SESSION_KEY.equals(key)) {
                        serviceSessionId = value;
                    }
                    if (ASP_SESSION_KEY.equals(key)) {
                        netSessionId = value;
                    }
                }
            }
            Map<String, Object> contentMap = VtuzxUtil.getObject(resultMap, "Context");
            this._token = new VtuzxKingdeeCloudToken(serviceSessionId, netSessionId, contentMap);
            return this;
        } else {
            if ("CheckPasswordPolicy".equals(VtuzxUtil.getString(resultMap, "MessageCode"))) {
                throw new VtuzxException("金蝶账号【" + _account.getAccount() + "】密码错误！");
            }
            throw new VtuzxException(IVtuzxConst.Msg_E_system);
        }
    }

    /**
     * 获取Token值
     *
     * @param key KEY
     * @return 返回值类型
     */
    public <T> T get(String key) {
        return VtuzxUtil.getObject(_token, key);
    }

    /**
     * 单据下推
     *
     * @param formId 业务类型表单ID
     * @param param 参数
     * @return 查询结果
     * @throws VtuzxException 异常
     */
    public List<VtuzxMap> push(String formId, VtuzxMap param) throws VtuzxException {
        return saveForm(KingdeeServiceKey.Push.toString(), formId, param);
    }

    /**
     * 单据保存
     *
     * @param formId 业务类型表单ID
     * @param param 参数
     * @return 查询结果
     * @throws VtuzxException 异常
     */
    public List<VtuzxMap> save(String formId, VtuzxMap param) throws VtuzxException {
        return saveForm(KingdeeServiceKey.Save.toString(), formId, param);
    }

    /**
     * 单据提交
     *
     * @param formId 业务类型表单ID
     * @param param 参数
     * @return 查询结果
     * @throws VtuzxException 异常
     */
    public List<VtuzxMap> submit(String formId, VtuzxMap param) throws VtuzxException {
        return saveForm(KingdeeServiceKey.Submit.toString(), formId, param);
    }

    /**
     * 单据审核
     *
     * @param formId 业务类型表单ID
     * @param param 参数
     * @return 查询结果
     * @throws VtuzxException 异常
     */
    public List<VtuzxMap> audit(String formId, VtuzxMap param) throws VtuzxException {
        return saveForm(KingdeeServiceKey.Audit.toString(), formId, param);
    }

    /**
     * 单据审核
     *
     * @param formId 业务类型表单ID
     * @param param 参数
     * @return 查询结果
     * @throws VtuzxException 异常
     */
    public List<VtuzxMap> toRelease(String formId, String status, VtuzxMap param) throws VtuzxException {
        return saveForm(KingdeeServiceKey.ExecuteOperation.toString(), formId, status, param);
    }

    /**
     * 查询单据接口
     *
     * @return 查询结果
     * @throws Exception 异常
     */
    public List<VtuzxMap> query(String formId, List<String> fieldList, String cond, String order, int start, int limit) throws Exception {
        _logger.debug("query form " + formId + " start!");
        VtuzxMap param = new VtuzxMap();
        param.append("FormId", formId);
        StringBuilder fieldKeys = new StringBuilder();
        for(String field: fieldList) {
            fieldKeys.append(",").append(field);
        }
        param.append("FieldKeys", fieldKeys.substring(1));
        if (VtuzxUtil.isEmpty(cond)) {
            param.append("FilterString", "");
        } else {
            param.append("FilterString", cond);
        }
        if (!VtuzxUtil.isEmpty(order)) param.append("OrderString", order);
        if (start > 0) param.append("StartRow", start);
        if (limit > 0) param.append("Limit", limit);

        List<VtuzxMap> resultList = new ArrayList<>();
        List<List<Object>> apiResList = billQuery(param);
        for(List<Object> apiRes: apiResList) {
            VtuzxMap detail = new VtuzxMap();
            for(int i = 0; i < fieldList.size(); i++) {
                detail.append(fieldList.get(i), apiRes.get(i));
            }
            resultList.add(detail);
        }
        _logger.debug("query form " + formId + " finish!");
        return resultList;
    }

    /**
     * 单据查询
     *
     * @param param 参数
     * @return 查询结果
     * @throws VtuzxException 异常
     */
    public List<List<Object>> billQuery(VtuzxMap param) throws VtuzxException {
        String formData = String.format("[\"%s\"]", VtuzxUtil.json2Str(param).replaceAll("\"", "\\\\\""));
        _logger.info(formData);
        String ret = execute(KingdeeServiceKey.BillQuery.toString(), formData);

        VtuzxMap temp = VtuzxUtil.str2Json("{t: " + ret + "}");
        if (temp == null) return null;

        List<List<Object>> resList = VtuzxUtil.getObject(temp, "t");
        if (resList != null && resList.size() > 0) {
            List<Object> firstList = resList.get(0);
            if (firstList != null && firstList.size() > 0 && (firstList.get(0) instanceof Map)) {
                @SuppressWarnings("unchecked")
                Map<String, Object> first = (Map<String, Object>)firstList.get(0);
                checkResult(first);
            }
        }
        return resList;
    }

    /**
     * 查询单据接口
     *
     * @return 查询结果
     * @throws Exception 异常
     */
    public VtuzxMap upload(String fileName, File file) throws Exception {
        if (_token == null) throw new VtuzxException(IVtuzxConst.Msg_E_system);
        try (FileInputStream input = new FileInputStream(file)) {
            byte[] buffer = new byte[READ_MAX_LEN];
            int readLen;
            String fileNameEncode = URLEncoder.encode(fileName, "UTF-8");
            int fileSize = 0;
            String fileId = "";
            while ((readLen = input.read(buffer)) != -1) {
                boolean last = readLen != READ_MAX_LEN;
                fileSize += readLen;
                String url = String.format("%sFileUpLoadServices/FileService.svc/upload2attachment/?fileName=%s&fileId=%s&token=%s&last=%s",
                        _account.getUrl(), fileNameEncode, fileId, _token.getToken(), last);

                Map<String, Object> result = uploadStream(url, fileName, buffer);
                _logger.debug("upload result:" + result);
                boolean success = VtuzxUtil.getBoolean(result, "Success");
                if (success) {
                    fileId = VtuzxUtil.getString(result, "FileId");
                }
            }
            return new VtuzxMap("fileId", fileId).append("fileSize", fileSize);
        }
    }

    /**
     * 单据保存
     *
     * @param subUrl 子网
     * @param formId 业务类型表单ID
     * @param param 参数
     * @return 查询结果
     * @throws VtuzxException 异常
     */
    private List<VtuzxMap> saveForm(String subUrl, String formId, VtuzxMap param) throws VtuzxException {
        _logger.debug("execute:" + subUrl + "start!\r\nformId:" + formId + "\r\nparam:" + VtuzxUtil.json2Str(param));
        String formData = String.format("[\"%s\",\"%s\"]", formId, VtuzxUtil.json2Str(param).replaceAll("\"", "\\\\\""));
        String ret = execute(subUrl, formData);
        _logger.debug("execute:" + subUrl + "end!" + ret);
        VtuzxMap res = VtuzxUtil.str2Json(ret);
        // 校验结果
        checkResult(res);
        Map<String, Object> response = VtuzxUtil.getObject(res, "Result");
        Map<String, Object> responseStatus = VtuzxUtil.getObject(response, "ResponseStatus");
        List<Map<String, Object>> entitys = VtuzxUtil.getObject(responseStatus, "SuccessEntitys");
        List<VtuzxMap> resultList = new ArrayList<>();
        for(Map<String, Object> entity: entitys) {
            resultList.add(new VtuzxMap(entity));
        }
        return resultList;
    }
    /**
     * 单据保存
     *
     * @param subUrl 子网
     * @param formId 业务类型表单ID
     * @param param 参数
     * @return 查询结果
     * @throws VtuzxException 异常
     */
    private List<VtuzxMap> saveForm(String subUrl, String formId, String status, VtuzxMap param) throws VtuzxException {
        _logger.debug("execute:" + subUrl + "start!\r\nformId:" + formId + "\r\nparam:" + VtuzxUtil.json2Str(param));
        String formData = String.format("[\"%s\",\"%s\",\"%s\"]", formId, status, VtuzxUtil.json2Str(param).replaceAll("\"", "\\\\\""));
        String ret = execute(subUrl, formData);
        _logger.debug("execute:" + subUrl + "end!" + ret);
        VtuzxMap res = VtuzxUtil.str2Json(ret);
        // 校验结果
        checkResult(res);
        Map<String, Object> response = VtuzxUtil.getObject(res, "Result");
        Map<String, Object> responseStatus = VtuzxUtil.getObject(response, "ResponseStatus");
        List<Map<String, Object>> entitys = VtuzxUtil.getObject(responseStatus, "SuccessEntitys");
        List<VtuzxMap> resultList = new ArrayList<>();
        for(Map<String, Object> entity: entitys) {
            resultList.add(new VtuzxMap(entity));
        }
        return resultList;
    }

    /**
     * 执行指令
     *
     * @param subUrl URL
     * @param param 参数
     * @throws VtuzxException 异常
     */
    private String execute(String subUrl, String param) throws VtuzxException {
        if (_token == null) throw new VtuzxException(IVtuzxConst.Msg_E_system);
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.MULTIPART_FORM_DATA);
        headers.add(SESSION_KEY, _token.getServiceSessionId());
        headers.add(ASP_SESSION_KEY, _token.getNetSessionId());

        MultiValueMap<String, Object> form = new LinkedMultiValueMap<>();
        setParameter(form, param);

        HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(form, headers);
        RestTemplate restTemplate = new RestTemplate();

        ResponseEntity<String> result = restTemplate.postForEntity(String.format("%s%s", _account.getUrl(), subUrl), httpEntity, String.class);
        if (!HttpStatus.OK.equals(result.getStatusCode()) || result.getBody() == null) {
            throw new VtuzxException(IVtuzxConst.Msg_E_system);
        }
        String body = result.getBody();
        _logger.debug("execute result:" + body);
        return body;
    }

    /**
     * 设置参数
     *
     * @param form 表单
     * @param params 参数
     */
    private void setParameter(MultiValueMap<String, Object> form, String params) {
        putFormItem(form, "useragent", "ApiClient");
        putFormItem(form, "version", "1.0");
        putFormItem(form, "nonce", "");
        putFormItem(form, "rid", Integer.toString(VtuzxUtil.uuid(true).hashCode()));
        putFormItem(form, "timestamp", new Date().toString());
        putFormItem(form, "format", "1");
        putFormItem(form, "parameters", params);
    }

    /**
     * 校验结果
     *
     * @param ret 返回值
     * @throws VtuzxException 异常
     */
    private void checkResult(Map<String, Object> ret) throws VtuzxException {
        Map<String, Object> response = VtuzxUtil.getObject(ret, "Result");
        Map<String, Object> responseStatus = VtuzxUtil.getObject(response, "ResponseStatus");
        boolean success = VtuzxUtil.getBoolean(responseStatus, "IsSuccess");
        List<Map<String, Object>> errors = VtuzxUtil.getObject(responseStatus, "Errors");
        if (!success) {
            throw new VtuzxException(VtuzxUtil.isEmpty(errors)?
                    IVtuzxConst.Msg_E_system: VtuzxUtil.getString(errors.get(0), "Message"));
        }
    }

    /**
     * 数据加入Form
     *
     * @param form Form
     * @param key Key
     * @param value 值
     */
    private void putFormItem(MultiValueMap<String, Object> form, String key, Object value) {
        List<Object> list = new ArrayList<>();
        list.add(value);
        form.put(key, list);
    }

    /**
     * 上传Stream
     *
     * @param url URL
     * @param fileName 文件名
     * @param content 正文
     * @return 上传结果
     * @throws VtuzxException 异常
     */
    private Map<String, Object> uploadStream(String url, String fileName, byte[] content) throws VtuzxException {
        HttpHeaders streamHeader = new HttpHeaders();
        streamHeader.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        streamHeader.setContentDispositionFormData("file", fileName);
        HttpEntity<ByteArrayResource> picturePart = new HttpEntity<>(new ByteArrayResource(content), streamHeader);
        RestTemplate restTemplate = new RestTemplate();
        ResponseEntity<String> result = restTemplate.exchange(url, HttpMethod.POST, picturePart, String.class);
        if (HttpStatus.OK.equals(result.getStatusCode()) && result.getBody() != null) {
            Map<String, Object> resMap = VtuzxUtil.str2Json(result.getBody());
            return VtuzxUtil.getObject(resMap, "Upload2AttachmentResult");
        } else {
            throw new VtuzxException(IVtuzxConst.Msg_E_system);
        }
    }

    //修改生产订单下达时间
    public int orderUpdate(String formId, String billNo, String updateTime) throws VtuzxException{
        return formUpdate(KingdeeServiceKey.OrderUpdate.toString(),formId,billNo,updateTime);

    }
    private int formUpdate(String subUrl, String formId,String billNo,String updateTime) throws VtuzxException {
        VtuzxMap parameters = new VtuzxMap();
        parameters.append("parameter","2023-09-01 21:09:09")
                .append("entryId","MO005937");
//        String formData = String.format("[\"%s\",\"%s\"]","2023-09-01 21:09:09","MO005937");
        String formData = String.format("[\"%s\",\"%s\"]",updateTime,billNo);
        String ret = executeOrder(subUrl,formData);

        return Integer.parseInt(ret);

    }

    //修改生产订单下达时间执行方法
    private String executeOrder(String subUrl, String param) throws VtuzxException {
        if (_token == null) throw new VtuzxException(IVtuzxConst.Msg_E_system);
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.MULTIPART_FORM_DATA);
        headers.add(SESSION_KEY, _token.getServiceSessionId());
        headers.add(ASP_SESSION_KEY, _token.getNetSessionId());
        MultiValueMap<String, Object> form = new LinkedMultiValueMap<>();
        setParameterOrder(form, param);
        HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(form, headers);
        RestTemplate restTemplate = new RestTemplate();
        ResponseEntity<String> result = restTemplate.postForEntity(String.format("%s%s", _account.getUrl(), subUrl), httpEntity, String.class);
        if (!HttpStatus.OK.equals(result.getStatusCode()) || result.getBody() == null) {
            throw new VtuzxException(IVtuzxConst.Msg_E_system);
        }
        String body = result.getBody();
        _logger.debug("execute result:" + body);
        return body;
    }

    /**
     * 设置参数(修改生产订单)
     *
     * @param form 表单
     * @param params 参数
     */
    private void setParameterOrder(MultiValueMap<String, Object> form, String params) {
        putFormItem(form, "useragent", "ApiClient");
        putFormItem(form, "version", "1.0");
        putFormItem(form, "nonce", "");
        putFormItem(form, "rid", Integer.toString(VtuzxUtil.uuid(true).hashCode()));
        putFormItem(form, "timestamp", new Date().toString());
        putFormItem(form, "format", "1");
        putFormItem(form, "parameters", params);
    }
}
